import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileSystemView;

import bugfixes.Fix;


public class BugFixer {
	
	public static String[] fixes = {"ImportFix", "ServerMessageFix", "GEMethodFix", "MouseFix", "ListenerFix"};
	
	public static String ls = System.getProperty("line.separator");
	
	public static File getInfDir() {
		return new File(getInfPath());
	}
	
	public static String getUnixHome() {
		final String home = System.getProperty("user.home");
		return home == null ? "~" : home;
	}
	
	public static String getInfPath() {
		final String env = System.getenv("INFINITY_HOME");
		if ((env == null) || env.isEmpty())
			return (getOS().contains("Windows") ? FileSystemView.getFileSystemView().getDefaultDirectory().getAbsolutePath() : getUnixHome()) + File.separator + "Infinity";
		else
			return env;
	}
	
	public static String getOS() {
		return System.getProperty("os.name");
	}
	
	public static String retardMode() { // thanks levest for name
		JFileChooser jfc = new JFileChooser();
		jfc.setFileFilter(new FileFilter() {

			@Override
			public boolean accept(File arg0) {
				return arg0.isDirectory() || arg0.getName().endsWith(".java");
			}

			@Override
			public String getDescription() {
				return "Java files";
			}
			
		});
		jfc.setAcceptAllFileFilterUsed(false);
	    jfc.setCurrentDirectory(getInfDir());

		jfc.setDialogTitle("Select runedev script to fix for infinity");
		int ret = jfc.showOpenDialog(null);
		if (ret == JFileChooser.APPROVE_OPTION) {
			File f = jfc.getSelectedFile();
			if (f != null)
				return f.getAbsolutePath();
		}
		return null;
	}
	
	public static void main(String[] args) {
		String loc = "";
		boolean gui = false;
		if (args.length < 1) {
			loc = retardMode();
			gui = true;
			//log("Please give location of java file to fix.");
			//return;
		}
		else {
			loc = args[0];
		}
		if (loc == null) {
			log("Given file location is null!");
			return;
		}
		File javah = new File(loc);
		if (!javah.exists()) {
			log("Java file given in input doesn't exist.");
			return;
		}
		if (!javah.getName().endsWith(".java")) {
			log("File given in input doesn't end in .java");
			return;
		}
		
		String path = javah.getAbsolutePath();
		
		String toPath = path.substring(0, path.lastIndexOf(File.separator)+1);
		
		String lastName = path.substring(path.lastIndexOf(File.separator)+1).replace(".java", "");
		
		File renameTo = new File(toPath + lastName + "_old.java");
		
		File newJava = new File(path);
		
		try {
			
			String fullJava = loadFile(javah);
			
			String oldCache = fullJava;
			
			for (String fix : fixes) {
				Fix search = (Fix) Class.forName("bugfixes." + fix).newInstance();
				String fixed = search.fixed(fullJava);
				if (!fixed.equals(fullJava))
					fullJava = search.fixed(fullJava);
			}
			
			if (oldCache.equals(fullJava)) {
				log("No fixes to do found. Are you sure '" + javah.getName() + "' doesn't compile?");
				return;
			}
			
			if (gui)
				JOptionPane.showMessageDialog(null, "Succesfully fixed errors in given java file. Trying to compile..");
			
			javah.renameTo(renameTo);
			
			if (newJava.exists())
				newJava.delete();
			
			newJava.createNewFile();
			
			BufferedWriter bw = new BufferedWriter(new FileWriter(newJava));
			bw.write(fullJava);
			bw.close();
			
			
			
		} catch (IOException e) {
			e.printStackTrace();
			return;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		try {
			compile(newJava, gui);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void log(String s) {
		System.out.println(s);
	}
	
	public static String loadFile(File f) throws IOException {
		BufferedReader bf = new BufferedReader(new FileReader(f));

		String file = "";
		String line = null;
		
		while ((line = bf.readLine()) != null) {
			file += line + ls;
		}
		
		bf.close();
		
		return file;
	}
	
	public static void compile(File f, boolean gui) throws IOException {
		
		File inf = findInfinity();
		
		if (inf == null) {
			if (gui)
				JOptionPane.showMessageDialog(null, "Couldn't find Infinity.jar in user.home so can't automatically compile.");
			System.err.println("Couldn't find Infinity.jar in Infinity folder so can't automatically compile.");
			return;
		}
		
		String line;
		String cmd = "javac -classpath " + inf.getAbsolutePath() + " " + f.getAbsolutePath();
		log("executing " + cmd);
		Process p = Runtime.getRuntime().exec(cmd);
		//Process p = Runtime.getRuntime().exec("ls");
		
		log("");
		log("--- Compiler error output ---");
		log("");
		
		BufferedReader input = new BufferedReader(new InputStreamReader(p.getErrorStream()));
		
		boolean errors = false;
		
		String errorsLog = "";
		
		while ((line = input.readLine()) != null) {
			log(line);
			errorsLog += line + ls;
			if (line.endsWith("error") || line.endsWith("errors"))
				errors = true;
		}
		
		if (errors) {
			new File("errors.txt").delete();
			BufferedWriter bw = new BufferedWriter(new FileWriter("errors.txt"));
			bw.write(errorsLog);
			bw.close();
		}
		
		log("");
		log("--- End of compiler error output ---");
		log("");
		if (!errors) {
			log("No errors in compiling :)");
			if (gui)
				JOptionPane.showMessageDialog(null, "No errors in compiling!");
		}
		else {
			log("Please send generated errors.txt to Waterwolf");
			if (gui)
				JOptionPane.showMessageDialog(null, "Error(s) in compiling! Please send generated errors.txt to Waterwolf!");
		}
		
		input.close();
	}
	
	public static File findInfinity() {
		File jar = new File(getInfPath() + File.separator + "Infinity.jar");
		if (jar.exists())
			return jar;
		
		return null;
	}
}
